/*
 * Copyright (C) 2010 mAPPn.Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.mol.market.common.download;

import java.io.File;
import java.util.HashMap;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.text.TextUtils;
import android.widget.RemoteViews;

import com.mol.market.R;
import com.mol.market.Session;
import com.mol.market.common.download.DownloadManager.Impl;
import com.mol.market.common.util.Utils;
import com.mol.market.ui_v4.ProductDetailActivity;

/**
 * This class handles the updating of the Notification Manager for the cases where there is an
 * ongoing download. Once the download is complete (be it successful or unsuccessful) it is no
 * longer the responsibility of this component to show the download in the notification manager.
 * 
 */
public class DownloadNotification {

    Context mContext;
    HashMap<String, NotificationItem> mNotifications;
    NotificationManager mNotificationManager;

    static final String LOGTAG = "DownloadNotification";

    static final String WHERE_RUNNING = "(" + DownloadManager.Impl.COLUMN_STATUS
            + " >= '100') AND (" + DownloadManager.Impl.COLUMN_STATUS + " <= '199') AND ("
            + DownloadManager.Impl.COLUMN_VISIBILITY + " IS NULL OR "
            + DownloadManager.Impl.COLUMN_VISIBILITY + " == '"
            + DownloadManager.Impl.VISIBILITY_VISIBLE + "' OR "
            + DownloadManager.Impl.COLUMN_VISIBILITY + " == '"
            + DownloadManager.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "')";

    static final String WHERE_COMPLETED = DownloadManager.Impl.COLUMN_STATUS + " >= '200' AND "
            + DownloadManager.Impl.COLUMN_VISIBILITY + " == '"
            + DownloadManager.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "'";

    static final String WHERE_OTA_COMPLETED = DownloadManager.Impl.COLUMN_STATUS + " >= '200' AND "
            + DownloadManager.Impl.COLUMN_SOURCE + " == '3' AND "
            + DownloadManager.Impl.COLUMN_VISIBILITY + " == '"
            + DownloadManager.Impl.VISIBILITY_VISIBLE + "' AND "
            + DownloadManager.Impl.COLUMN_MIME_TYPE + " == '" + Constants.MIMETYPE_APK + "'";

    static final String WHERE_BAD_COMPLETED = DownloadManager.Impl.COLUMN_STATUS
            + " >= '400' AND (" + DownloadManager.Impl.COLUMN_VISIBILITY + " == '"
            + DownloadManager.Impl.VISIBILITY_VISIBLE + "' OR "
            + DownloadManager.Impl.COLUMN_VISIBILITY + " == '"
            + DownloadManager.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "') AND "
            + DownloadManager.Impl.COLUMN_MIME_TYPE + " == '" + Constants.MIMETYPE_APK + "'";

    public static final String PUBLIC_WHERE_OTA_COMPLETED = DownloadManager.Impl.COLUMN_STATUS
            + " >= '200' AND " + DownloadManager.Impl.COLUMN_SOURCE + " == '3' AND "
            + DownloadManager.Impl.COLUMN_MIME_TYPE + " == '" + Constants.MIMETYPE_APK + "'";

    /**
     * This inner class is used to collate downloads that are owned by the same application. This is
     * so that only one notification line item is used for all downloads of a given application.
     * 
     */
    static class NotificationItem {
        // This first db _id for the download for the app
        int mId;
        // current downloaded bytes
        long mCurrentBytes = 0;
        // total size
        long mTotalBytes = 0;
        // the number of title
        int mTitleCount = 0;
        // App package name
        String mPackageName;
        // download titles.

        String[] mTitles = new String[2];

        String mPausedText = null;

        /*
         * Add a second download to this notification item.
         */
        void addItem(String title, long currentBytes, long totalBytes) {
            mCurrentBytes += currentBytes;
            if (totalBytes <= 0 || mTotalBytes == -1) {
                mTotalBytes = -1;
            } else {
                mTotalBytes += totalBytes;
            }
            if (mTitleCount < 2) {
                mTitles[mTitleCount] = title;
            }
            mTitleCount++;
        }
    }

    /**
     * Constructor
     * 
     * @param ctx
     *            The context to use to obtain access to the Notification Service
     */
    DownloadNotification(Context ctx) {
        mContext = ctx;
        mNotifications = new HashMap<String, NotificationItem>();
        mNotificationManager = (NotificationManager) mContext
                .getSystemService(Context.NOTIFICATION_SERVICE);
    }

    /*
     * Clear all notifications
     */
    public void clearAllNotification() {
        if (mNotificationManager != null) {
            mNotificationManager.cancelAll();
        }
    }

    /*
     * Cancel notification use id
     */
    public void cancelNotification(long id) {
        if (mNotificationManager != null) {
            mNotificationManager.cancel((int) id);
        }
    }

    /*
     * Update the notification ui.
     */
    public void updateNotification() {
        updateActiveNotification();
        updateCompletedNotification();
        updateOtaNotification();
    }

    private void updateActiveNotification() {
        // Active downloads
        Cursor c = mContext.getContentResolver().query(
                DownloadManager.Impl.CONTENT_URI,
                new String[] { DownloadManager.Impl._ID, DownloadManager.Impl.COLUMN_TITLE,
                        DownloadManager.Impl.COLUMN_NOTIFICATION_PACKAGE,
                        DownloadManager.Impl.COLUMN_CURRENT_BYTES,
                        DownloadManager.Impl.COLUMN_TOTAL_BYTES }, WHERE_RUNNING, null,
                DownloadManager.Impl._ID);

        if (c == null) {
            return;
        }

        // Columns match projection in query above
        final int idColumn = 0;
        final int titleColumn = 1;
        final int ownerColumn = 2;
        final int currentBytesColumn = 3;
        final int totalBytesColumn = 4;

        // Collate the notifications
        mNotifications.clear();
        for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
            String packageName = c.getString(ownerColumn);
            int max = c.getInt(totalBytesColumn);
            int progress = c.getInt(currentBytesColumn);
            String title = c.getString(titleColumn);
            if (title == null || title.length() == 0) {
                title = mContext.getResources().getString(R.string.download_unknown_title);
            }
            if (mNotifications.containsKey(packageName)) {
                mNotifications.get(packageName).addItem(title, progress, max);
            } else {
                NotificationItem item = new NotificationItem();
                item.mId = c.getInt(idColumn);
                item.mPackageName = packageName;
                item.addItem(title, progress, max);
                mNotifications.put(packageName, item);
            }
        }
        c.close();

        // Add the notifications
        for (NotificationItem item : mNotifications.values()) {

//          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
//
//            final Notification.Builder builder = new Notification.Builder(mContext);
//            boolean hasPausedText = (item.mPausedText != null);
//            int iconResource = android.R.drawable.stat_sys_download;
//            if (hasPausedText) {
//              iconResource = android.R.drawable.stat_sys_warning;
//            }
//            builder.setSmallIcon(iconResource);
//            builder.setOngoing(true);
//
//            StringBuilder title = new StringBuilder(item.mTitles[0]);
//            if (item.mTitleCount > 1) {
//              title.append(mContext.getString(R.string.notification_filename_separator));
//              title.append(item.mTitles[1]);
//              if (item.mTitleCount > 2) {
//                title.append(mContext.getString(R.string.notification_filename_extras,
//                    new Object[] { Integer.valueOf(item.mTitleCount - 2) }));
//              }
//            }
//            builder.setContentTitle(title);
//
//            if (hasPausedText) {
//              builder.setContentText(item.mPausedText);
//            } else {
//              builder.setProgress(
//                  (int) item.mTotalBytes, (int) item.mCurrentBytes,
//                  item.mTotalBytes == -1);
//              builder.setContentInfo(
//                  getDownloadingText(item.mTotalBytes, item.mCurrentBytes)
//              );
//            }
//
//            Intent intent = getListIntent();
//            builder.setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0));
//
//            mNotificationManager.notify(item.mId, builder.getNotification());
//
//          } else {
            // Build the notification object
            Notification n = new Notification();
            n.defaults = 0;
            if (item.mPausedText == null) {
              n.icon = android.R.drawable.stat_sys_download;
            } else {
              n.icon = android.R.drawable.stat_sys_warning;
            }
            n.flags |= Notification.FLAG_ONGOING_EVENT;

            // Build the RemoteView object
            RemoteViews expandedView = new RemoteViews("com.mol.market",
                R.layout.status_bar_ongoing_event_progress_bar);
            StringBuilder title = new StringBuilder(item.mTitles[0]);
            if (item.mTitleCount > 1) {
              title.append(mContext.getString(R.string.notification_filename_separator));
              title.append(item.mTitles[1]);
              n.number = item.mTitleCount;
              if (item.mTitleCount > 2) {
                title.append(mContext.getString(R.string.notification_filename_extras,
                    new Object[] { Integer.valueOf(item.mTitleCount - 2) }));
              }
            }

            expandedView.setTextViewText(R.id.title, title);
            expandedView.setProgressBar(R.id.progress_bar, (int) item.mTotalBytes,
                (int) item.mCurrentBytes, item.mTotalBytes == -1);
            expandedView.setTextViewText(R.id.progress_text,
                getDownloadingText(item.mTotalBytes, item.mCurrentBytes));
            expandedView.setImageViewResource(R.id.appIcon, android.R.drawable.stat_sys_download);
            n.contentView = expandedView;

            Intent intent = getListIntent();
            n.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);

            mNotificationManager.notify(item.mId, n);
//          }
        }
    }

    private void updateCompletedNotification() {
        // Completed downloads
        Cursor c = mContext.getContentResolver().query(
                DownloadManager.Impl.CONTENT_URI,
                new String[] { DownloadManager.Impl._ID, 
                        DownloadManager.Impl.COLUMN_TITLE,
                        DownloadManager.Impl.COLUMN_STATUS,
                        DownloadManager.Impl.COLUMN_LAST_MODIFICATION,
                        DownloadManager.Impl.COLUMN_DESTINATION ,
                        DownloadManager.Impl.COLUMN_PACKAGE_NAME}, WHERE_COMPLETED, null,
                DownloadManager.Impl._ID);

        if (c == null) {
            return;
        }

        // Columns match projection in query above
        final int idColumn = 0;
        final int titleColumn = 1;
        final int statusColumn = 2;
        final int lastModColumnId = 3;
        final int destinationColumnId = 4;
        final int packageColumnId = 5;

        for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
            // Add the notifications
            Notification n = new Notification();
            n.defaults = 0;
            n.icon = android.R.drawable.stat_sys_download_done;

            String title = c.getString(titleColumn);
            if (title == null || title.length() == 0) {
                title = mContext.getResources().getString(R.string.download_unknown_title);
            }

            Uri contentUri = Uri.parse(DownloadManager.Impl.CONTENT_URI + "/" + c.getInt(idColumn));

            String caption;
            Intent intent;
            if (DownloadManager.Impl.isStatusError(c.getInt(statusColumn))) {
                caption = handleErrorMessage(c.getInt(statusColumn));
                intent = getDetailIntent(c.getString(packageColumnId));
            } else {
                caption = mContext.getResources()
                        .getString(R.string.notification_download_complete);
                if (c.getInt(destinationColumnId) != DownloadManager.Impl.DESTINATION_EXTERNAL) {
                    intent = getListIntent();
                } else {
                    intent = getOpenIntent(contentUri);
                }
            }

            n.setLatestEventInfo(mContext, title, caption,
                    PendingIntent.getActivity(mContext, c.getInt(idColumn), intent, 0));
            n.deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
            n.flags |= Notification.FLAG_AUTO_CANCEL;
            n.when = c.getLong(lastModColumnId);

            setCompletedNotification(contentUri);
            mNotificationManager.notify(c.getInt(idColumn), n);
        }
        c.close();
    }

    public void clearBadNotification() {

        Utils.D("start clear bad notifications");

        // Clear bad notifications
        Cursor c = mContext.getContentResolver().query(DownloadManager.Impl.CONTENT_URI, null,
                WHERE_BAD_COMPLETED, null, DownloadManager.Impl._ID);

        if (c == null) {
            return;
        }

        final int idColumn = c.getColumnIndexOrThrow(DownloadManager.Impl.COLUMN_ID);
        for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {

            ContentValues v = new ContentValues();
            v.put(DownloadManager.Impl.COLUMN_VISIBILITY, DownloadManager.Impl.VISIBILITY_HIDDEN);
            mContext.getContentResolver().update(DownloadManager.Impl.CONTENT_URI, v, null, null);
            mNotificationManager.cancel(c.getInt(idColumn));
        }
        c.close();
    }

    private void updateOtaNotification() {

        // Completed OTA downloads
        Cursor c = mContext.getContentResolver().query(DownloadManager.Impl.CONTENT_URI,
                new String[] { DownloadManager.Impl._ID, DownloadManager.Impl.COLUMN_DATA, },
                WHERE_OTA_COMPLETED, null, DownloadManager.Impl._ID);

        if (c == null) {
            return;
        }

        // Columns match projection in query above
        final int idColumn = 0;
        final int filenameColumnId = 1;

        if (c.moveToFirst()) {

            String filePath = c.getString(filenameColumnId);
            if (!TextUtils.isEmpty(filePath)) {
                mNotificationManager.cancel(c.getInt(idColumn));
                try {
                    Session.get(mContext).mIsDownloadOta = false;
                    Utils.installApk(mContext, new File(filePath));
                } catch (Exception e) {
                    Utils.E("ota exception", e);
                    c.close();
                    return;
                }
            }

            ContentValues values = new ContentValues();
            values.put(Impl.COLUMN_VISIBILITY, Impl.VISIBILITY_HIDDEN);
            mContext.getContentResolver().update(DownloadManager.Impl.CONTENT_URI, values,
                    Impl.COLUMN_ID + " = " + c.getLong(idColumn), null);
        }
        c.close();
    }

    private String handleErrorMessage(int status) {
        if (DownloadManager.Impl.STATUS_BAD_REQUEST == status) {
            return mContext.getString(R.string.download_alert_url);
        } else if (DownloadManager.Impl.STATUS_NOT_ACCEPTABLE == status) {
            return mContext.getString(R.string.download_error_file_type);
        } else if (DownloadManager.Impl.STATUS_LENGTH_REQUIRED == status
                || DownloadManager.Impl.STATUS_PRECONDITION_FAILED == status
                || DownloadManager.Impl.STATUS_UNKNOWN_ERROR == status) {
            return mContext.getString(R.string.download_alert_service);
        } else if (DownloadManager.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR == status
                || DownloadManager.Impl.STATUS_FILE_ERROR == status) {
            return mContext.getString(R.string.download_alert_client);
        } else if (DownloadManager.Impl.STATUS_CANCELED == status) {
            return mContext.getString(R.string.download_alert_cancel);
        } else if (DownloadManager.Impl.STATUS_UNHANDLED_REDIRECT == status
                || DownloadManager.Impl.STATUS_UNHANDLED_HTTP_CODE == status
                || DownloadManager.Impl.STATUS_HTTP_EXCEPTION == status
                || DownloadManager.Impl.STATUS_HTTP_DATA_ERROR == status
                || DownloadManager.Impl.STATUS_TOO_MANY_REDIRECTS == status) {
            return mContext.getString(R.string.download_alert_network);
        } else if (DownloadManager.Impl.STATUS_DEVICE_NOT_FOUND_ERROR == status) {
            return mContext.getString(R.string.download_alert_no_sdcard);
        } else if (DownloadManager.Impl.STATUS_INSUFFICIENT_SPACE_ERROR == status) {
            return mContext.getString(R.string.download_alert_no_space);
        } else {
            return mContext.getString(R.string.download_error);
        }
    }

    /*
     * Helper function to build the downloading text.
     */
    private String getDownloadingText(long totalBytes, long currentBytes) {
        if (totalBytes <= 0) {
            return "";
        }
        long progress = currentBytes * 100 / totalBytes;
        StringBuilder sb = new StringBuilder();
        sb.append(progress);
        sb.append('%');
        return sb.toString();
    }

    /**
     * 设置当前Uri对应下载条目notifation属性为隐藏
     * 
     * @param uri
     *            此记录在数据库中的uri
     */
    private void setCompletedNotification(Uri uri) {
        Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);
        if (cursor == null) {
            return;
        }
        try {
            if (!cursor.moveToFirst()) {
                return;
            }
            ContentValues values = new ContentValues();
            values.put(DownloadManager.Impl.COLUMN_VISIBILITY,
                    DownloadManager.Impl.VISIBILITY_HIDDEN);
            mContext.getContentResolver().update(uri, values, null, null);
        } finally {
            cursor.close();
        }
    }

    /**
     * 获取打开已完成下载apk的 launcher
     * 
     * @param contentUri
     *            词条下载记录的数据库Uri
     * @return Intent
     */

    private Intent getOpenIntent(Uri contentUri) {
        Cursor cu = mContext.getContentResolver().query(contentUri, null, null, null, null);
        if (cu == null) {
            return new Intent();
        } else if (!cu.moveToFirst()) {
            return new Intent();
        }
        String filename = cu.getString(cu.getColumnIndexOrThrow(DownloadManager.Impl.COLUMN_DATA));
        String mimetype = cu.getString(cu
                .getColumnIndexOrThrow(DownloadManager.Impl.COLUMN_MIME_TYPE));
        int destination = cu.getInt(cu
                .getColumnIndexOrThrow(DownloadManager.Impl.COLUMN_DESTINATION));

        if (destination == Constants.DESTINATION_EXTERNAL && !Utils.isSdcardWritable()) {
            // SDCard 没有挂载，无法进行安装操作
            Utils.makeEventToast(mContext, mContext.getString(R.string.warning_sdcard_unmounted),
                    false);
            return new Intent();
        }

        Uri path = Uri.parse(filename);
        // If there is no scheme, then it must be a file
        if (path.getScheme() == null) {
            path = Uri.fromFile(new File(filename));
        }

        Intent activityIntent = new Intent(Intent.ACTION_VIEW);
        activityIntent.setDataAndType(path, mimetype);
        activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        return activityIntent;
    }

    /**
     * 获取应用管理页面Intent
     * 
     * @return Intent
     */

    private Intent getListIntent() {
        Intent intent = new Intent(com.mol.market.Constants.BROADCAST_CLICK_INTENT);
        intent.putExtra(com.mol.market.Constants.CLICK_DOWNLOADING, true);
        return intent;
    }
    
    

    private Intent getDetailIntent(String pid) {
        Intent detailIntent = new Intent(mContext, ProductDetailActivity.class);
        detailIntent.putExtra(com.mol.market.Constants.EXTRA_PACKAGE_NAME, pid);
        return detailIntent;
    }

}